﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Utils
{
    /// <summary>
    /// 循环队列
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class CircularQueue<T> : IEnumerable<T>, IReadOnlyCollection<T>, ICollection
    {
        protected int capacity;
        protected T[] array = null;
        protected int readPosition ;
        protected int writePosition ;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="capacity">队列大小</param>
        /// <param name="queueFullContinueWrite">队列满后是否能继续入列</param>
        public CircularQueue(int capacity)
        {
            this.capacity = capacity;
            Clear();
        }

        /// <summary>
        /// 入列,队列满后会覆盖旧数据
        /// </summary>
        /// <param name="item"></param>
        public void Enqueue(T item)
        {
            array[writePosition] = item;
            writePosition++;            
            if (writePosition == array.Length) writePosition = 0;
            if (Count<capacity)  
            {
                Count++;
            }
            else  //队列已满
            {
                readPosition = writePosition;
            }
        }

        /// <summary>
        /// 出列,队列为空时会抛异常
        /// </summary>
        /// <returns></returns>
        public T Dequeue()
        {
            var data = Peek();
            readPosition++;
            Count--;
            if (readPosition == array.Length) readPosition = 0;
            return data;
        }

        /// <summary>
        /// 获取队列当前数据但不出列
        /// </summary>
        /// <returns></returns>
        public T Peek()
        {
            if (Count == 0) throw new InvalidOperationException($"The collections is empty");
            var data = array[readPosition];
            return data;
        }

        /// <summary>
        /// 清空队列
        /// </summary>
        public void Clear()
        {
            array = new T[capacity];
            readPosition = 0;
            writePosition = 0;
            Count = 0;
        }

        public int Count { get; private set; }

        public bool IsSynchronized => false;

        public object SyncRoot => null;

        public void CopyTo(Array array, int index)
        {
            var copyingIndex = index;
            foreach (T data in this)
            {
                array.SetValue(data, copyingIndex);
                copyingIndex++;
            }
        }
        public IEnumerator<T> GetEnumerator()
        {
            if (writePosition > readPosition)
            {
                for (var i = readPosition; i < writePosition; i++)
                {
                    yield return array[i];
                }
            }
            else if (Count > 0)
            {
                for (var i = readPosition; i < this.array.Length; i++)
                {
                    yield return array[i];
                }
                var copiedLength = this.array.Length - readPosition;
                for (var i = 0; i < writePosition; i++)
                {
                    yield return array[i];
                }
            }
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

    }
}
